package moa.structure;

import java.awt.event.ItemListener;
import java.util.*;

/**
 * <p>
 *  This class modelises a sequence = an ordered set of itemsets
 * </p>
 */
public class SequenceInstance implements Cloneable, Comparable
{
	  /**
	   * <p>
	   *  This is the list of ItemSets contined in our sequence
	   * </p>
	   */
	  public List<ItemSet> itemSetList = null;

	  /**<p>
	   * The support of the actual sequence
	   * </p>
	   */
	  public double support = 0;

//******************************************************************************************************************
//Constructor of the class Sequence
//******************************************************************************************************************
	
	  /**<p>
	   * Creates a new Sequence with an empty list of itemsets
	   * </p>
	   */
	  public SequenceInstance() 
	  {
		  itemSetList = new ArrayList<ItemSet>();
	  }

	  /**<p>
	   * Creates a new Sequence and insert an itemset in it
	   * @param is : the itemset inserted in the Sequence
	   * </p>
	   */
	  public SequenceInstance(ItemSet is) 
	  {
		  itemSetList = new ArrayList<ItemSet>();
		  itemSetList.add(0, is);
	  }

	  /**<p>
	   * Creates a new Sequence and insert a list of itemset in it
	   * @param is : the itemset inserted in the Sequence
	   * </p>
	   */
	  public SequenceInstance(List<ItemSet> listOfItemSets) 
	  {
		  itemSetList = listOfItemSets;
	  }

	  
//******************************************************************************************************************
//Accessors of the class Sequence
//******************************************************************************************************************
	  
	  /**<p>
	   * @return the indexth ItemSet of the Sequence
	   * </p>
	   */
	  public ItemSet getItemSetAt(int index)
	  {
		  if (index < itemSetList.size())
		  {
			  return (itemSetList.get(index));
		  }
		  return null;
	  }
	  
	  /**<p>
	   * @return the number of itemset in the sequence
	   * </p>
	   */
	  public int getSize()
	  {
		  return (itemSetList.size());
	  }
	  
	  /**<p>
	   * @return the support of the sequence
	   * </p>
	   */
	  public double getSupport()
	  {
		  return support;
	  }
	  
	  /**<p> 
	   * Set de support of the current sequence
	   * </p>
	   */
	  public void setSupport(double support)
	  {
		  this.support = support;
	  }

//******************************************************************************************************************
//Methods of the class Sequence
//******************************************************************************************************************
	  
	  /**<p>
	   * This function adds an ITEM at the end of the last itemset of the sequence
	   * </p>
	   */
	  public void add(int item) 
	  {
		  //if the sequence is not empty we add the item at the end of the last itemset
		  if (!itemSetList.isEmpty())
		  {
			  itemSetList.get(itemSetList.size()-1).addItem(item);
		  }
		  //else we add an itemset built with the given item
		  else
		  {
			  add(new ItemSet(item));
		  }
	  }	 
	  
	  
	  /**<p>
	   * This function adds a new itemSet at the end of the itemSet list
	   * </p>
	   */
	  public void add(ItemSet is) 
	  {
	    itemSetList.add(is);
	  }	 
	  
	  
	  /**<p>
	   * This function adds a new itemSet at the beginning of the itemSet list
	   * </p>
	   */
	  public void addFront(ItemSet is) 
	  {
	    itemSetList.add(0, is);
	  }
	  
	  
	  /**<p>
	   * This function deletes the latest item in the itemSet list
	   * </p>
	   */
	   public void deleteLastItem() 
	   {
	     // We get the latest itemSet
	     int len = itemSetList.size();
	     if (len == 0) 
	     {
	       return;
	     }

	     ItemSet is = itemSetList.get(len - 1);
	     int lenLastItemSet = is.itemList.size();
	     if (lenLastItemSet > 1)
	     {
	    	 //we delete the latest item
		     is.itemList.remove(lenLastItemSet - 1);
	     }
	     else
	     {
	    	 //we delete the itemSet itself (because it is a 1-itemSet)
		     itemSetList.remove(is);
	     }
	   }
	   
	   
	   /**<p>
	    * This function clears the itemSet list
	    * </p>
	    */
	   public void reset() 
	   {
		   itemSetList.clear();
	   }
	   
	   /**<p>
		   * return how many items compose the sequence.
		   * @return the support of the sequence
		   * </p>
		   */
		  public int getNbItem ()
		  {
			  int i = 0;
			  for (int j = 0; j < itemSetList.size ();j++)
			  {
				  i += (int)itemSetList.get(j).getSize();
			  }
			  return i;
		  }
	   
	   /**<p> 
	    * This method test if the sequence is included in the parameter sequence
	    * @return a boolean
	    * </p>
	    */
	   public boolean isIncluded (SequenceInstance seq)
	   {
		   if (this.getNbItem() == 0)
			   return true;
		   //boolean res = false;
		   if (this.getNbItem() > seq.getNbItem() && this.getSize() > seq.getSize())
			   return false;
		   
		   int debut = 0;
		   boolean inter = false;
		   for (int i = 0; i < itemSetList.size(); i++)
		   {
			   for (int j = debut; j < seq.getSize(); j++)
			   {
				   ItemSet i1 = seq.getItemSetAt(j);
				   ItemSet i2 = itemSetList.get(i);
				   if (i1.contains(i2))
				   {
					   inter = true;
					   debut = j+1;
					   break;
				   }
			   }
			   if (!inter)
				   return false;
			   inter = false;
		   }
		   return true;
	   }

  
//******************************************************************************************************************
//Other methods
//****************************************************************************************************************** 


	   /**<p> 
	    * This method is called in order to duplicate a sequence : it is faster than instanciating a new sequence
	    * @return the cloned sequence
	    * </p>
	    */
	   public Object clone() 
	   {
		   Object sequence = null;
		   try 
		   {
			   //In order to clone a sequence we have to call the super method clone(),then we clone the arrayList containing each 
			   //and finally we clone each element of this arrayList (these are itemsets)
			   sequence = super.clone();
			   ((SequenceInstance)(sequence)).itemSetList = (ArrayList<ItemSet>) ((ArrayList<ItemSet>)itemSetList).clone();
			   for (int i=0; i< ((SequenceInstance)(sequence)).getSize(); i++)
			   {
				   ((SequenceInstance)(sequence)).itemSetList.set(i, (ItemSet)((itemSetList.get(i)).clone()));
			   }
			   
		   }
		   catch (CloneNotSupportedException e) 
		   {
			   throw new InternalError(e.toString()); 
		   }
		   return sequence;
	   }
	   
	   
	   public String toString() 
	   {
		   String str = "[";
		   for (int i=0; i<getSize(); i++)
		   {
			   str +=  getItemSetAt(i) ;
		   }
		   str +=  "]";
		   return str;
	   }

	public int compareTo(Object o) 
	{
		String act = this.toString();
		String obj = ((Sequence)o).toString();
		if (act.length() < obj.length())
			return -1;
		else if (act.length() > obj.length())
			return 1;
		else 
			return act.compareTo(obj);
	}

}
